#include "stdafx.h"
#include "FindCode.h"

int g_min = 0;
int g_max = 0;

//************************************
// Method:    crop
// FullName:  FindCode::crop
// Access:    public 
// Returns:   void
// Qualifier:
// Parameter: IplImage * image		--image to work with
// Parameter: IplImage * rawcrop	--storage of cropped codeblock
// Parameter: IplImage * normalized	--storage of normalized codeblock
// Parameter: int type				--type of image (telelens=0, trilens=1)
// Parameter: int codeIndex			--used for trilens, when more than one codeblock exists in one image
//
// Description: searches for codeblock in predefined area
//				uses cvMatchTemplate for that purpose
//************************************
void FindCode::crop(IplImage *image, IplImage *rawcrop, IplImage *normalized, int type, int codeIndex)
{
	int startx, starty;
	CvPoint endpoints = Init::getROI();
	
	type = 0 ? starty=10100 : starty=9500;

	startx=1+codeIndex*Init::getOffset();
	
	double minVal, maxVal;
	CvPoint minLoc;
	CvPoint maxLoc;
	
	

	cvSetImageROI(image,cvRect(startx,starty,endpoints.x,endpoints.y));

	IplImage *templ = cvLoadImage("templ3.tif",0);
	IplImage *templResult = cvCreateImage(cvSize(endpoints.x - templ->width + 1, endpoints.y - templ->height + 1), IPL_DEPTH_32F, 1);
	
	//match region with template. Max value should be first pixel of code block
	cvMatchTemplate(image, templ, templResult, CV_TM_CCOEFF);
	cvMinMaxLoc(templResult, &minVal, &maxVal, &minLoc, &maxLoc); 
	
	cvResetImageROI(image);
	
	//saving code block within a new image
	for (int i=0; i<Init::getCodeblock().x; i++)
	{
		for (int j=0; j<Init::getCodeblock().y; j++)
		{
			Pixel pix = ImageUtils::getPixel(image,startx+j+maxLoc.x-5,i+maxLoc.y+starty-5,normalized->nChannels);
			FindCode::minMax(pix);
			pix.y=i;
			pix.x=j;
			ImageUtils::setPixel(rawcrop,pix);
			
		}
	}

	//threshold image of code block
	if (Init::getDebug())
	{
		cvNamedWindow("CodeBlock", CV_WINDOW_AUTOSIZE);
		cvShowImage("CodeBlock", rawcrop);
		cvWaitKey(0);
		cvDestroyWindow("CodeBlock");
	}

	//make the code image binary
	normalize(rawcrop, normalized, Init::getParts().x, Init::getParts().y);

	
	cvReleaseImage(&templ);
	cvReleaseImage(&templResult);
}



//************************************
// Method:    minMax
// FullName:  FindCode::minMax
// Access:    private static 
// Returns:   void
// Qualifier:
// Parameter: Pixel pix		--actual pixel
//
// Description: determines the min & max value of the code block
//************************************
void FindCode::minMax(Pixel pix)
{
	int val = pix.getValue();
	if (val < g_min)
		g_min = val;
	else if (val > g_max)
		g_max = val;
}


//************************************
// Method:    normalize
// FullName:  FindCode::normalize
// Access:    private static 
// Returns:   void
// Qualifier:
// Parameter: IplImage * crop		--image to normalize
// Parameter: IplImage * normalized --storage for result
// Parameter: int partsx			--ammount of parts in x direction
// Parameter: int partsy			--ammount of parts in y direction
//
// Description: uses threshold to make a monocrom image of codeblock
//************************************
void FindCode::normalize(IplImage *crop, IplImage *normalized, int partsx, int partsy)
{
	cvZero(normalized);
	int thresh = (g_min+g_max)/4;

	//go through given part of image
	for (int k=1; k<=partsx; k++)
	{
		for (int l=1; l<=partsy; l++)
		{
			//get threshold
			thresh = histogram(crop, partsx, k, partsy, l);

			for (int i=(l-1)*(crop->height/partsy); i<l*(crop->height/partsy); i++)
			{
				for (int j=(k-1)*(crop->width/partsx); j<k*(crop->width/partsx); j++)
				{
					Pixel pix = ImageUtils::getPixel(crop,j,i,normalized->nChannels);
					if (pix.getValue() < thresh)
						ImageUtils::setPixel(normalized,Pixel(cvPoint(j,i),0,0,0,0,3));
					else
						ImageUtils::setPixel(normalized,Pixel(cvPoint(j,i),255,255,255,255,3));
				}
			}
			//cvThreshold(crop,normalized,thresh,255,CV_THRESH_BINARY);
		}
	}
	cvWaitKey(0);
	cvDestroyAllWindows();
}



//************************************
// Method:    histogram
// FullName:  FindCode::histogram
// Returns:   int
// Parameter: IplImage * image	--Image to make histrogram of
// Parameter: int partsx		--total ammount of parts in x direction
// Parameter: int actPartx		--actual accessed part in x direction
// Parameter: int partsy		--total ammount of parts in y direction
// Parameter: int actParty		--actual accessed part in y direction
//
// Description: calculates histogram for whole or part of an image,
//				runns through hist. to determine best point for threshold
//************************************
int FindCode::histogram(IplImage *image, int partsx, int actPartx, int partsy, int actParty)
{
	int hist[765];
	int hist2[255];
	int median[3];
	int average=0;
	int highest=0;

	//get pixelvalues, calculate histogram
	for (int i=0; i<765; i++)
		hist[i]=0;
	
	for (int i=(actParty-1)*(image->height/partsy); i<actParty*(image->height/partsy)-1; i++)
	{
		for (int j=(actPartx-1)*(image->width/partsx); j<actPartx*(image->width/partsx)-1; j++)
		{
			Pixel pix = ImageUtils::getPixel(image,j,i,image->nChannels);
			hist[pix.getValue()]++;
		}
	}

	IplImage *test = cvCreateImage(cvSize(765, 210), IPL_DEPTH_32F, 3);
	cvZero(test);
	
	int total=0;
	int pos=0;
	int mini=0, maxi=0, maxval=0;
	int count = 0;
	for (int i=0; i<255; i++)
		hist2[i]=0;

	//normalize histogram
	for (int i=0; i<765; i++)
	{
		average += hist[i];
		count++;

		if (count == 3)
		{
			count = 0;
			hist2[(i-3)/3]=average/3;
			average=0;
		}
		
	}

	//determine highest value and last value != 0 (equals brightest value)
	for (int i=254; i>=0; i--)
	{
		if (hist2[i]>0 && mini==0)
			mini=i;
		if (hist2[i]>maxval)
		{
			maxval=hist2[i];
			maxi=i;
		}
		/*total+=hist[i];
		if (total>(image->height/partsy*image->width/partsx)/4)
		{
			pos=i;
			i=0;
		}*/
	}

	//threshold = 1/5 between highest and brightest value
	pos=maxi+(mini-maxi)/4;

	//debug
	if (Init::getDebug())
	{
		std::string st;
		std::stringstream out;
		int toRight;
		for (int i=0; i<255; i++)
		{
			for (int j=0; j<3; j++)
			{
			/*historam-image:
			**hist. values:		white
			**threshold value:	red
			**maximum & minimum(!=0) value:	green*/
			if (i!=pos && i!=mini && i!=maxi)
				cvLine(test, cvPoint(i*3+j+1,205),cvPoint(i*3+j+1, 205-(hist2[i]*200)/hist2[maxi]), cvScalar(255,255,255,0), 1, 1, 0);
			else if (i==pos)
				cvLine(test, cvPoint(i*3+j+1,205),cvPoint(i*3+j+1, 5), cvScalar(0,0,255,0), 1, 1, 0);
			else if (i==mini || i==maxi)
				cvLine(test, cvPoint(i*3+j+1,205),cvPoint(i*3+j+1, 5), cvScalar(0,255,0,0), 1, 1, 0);
			}
		}
	
		st="Histogram";
		out<<(actPartx-1)*partsy+actParty;
		st+=out.str();
		cvNamedWindow(st.c_str(), 0);
		cvShowImage(st.c_str(), test);
		cvResizeWindow(st.c_str(),test->width/3,test->height/3);
		cvMoveWindow(st.c_str(),((((actPartx-1)*partsy+actParty)-1)/4)*((test->width/3)+25),(((((actPartx-1)*partsy+actParty)-1)%4)*test->height)/2);
 		//cvMoveWindow(st.c_str(),0,0);
		/*
		cvWaitKey(0);
				cvDestroyWindow(st.c_str());*/
		
//		cout<<pos<<" -min"<<mini<<" -max"<<maxi<<" -maxval"<<hist[maxi]<<endl;
	}
	cvReleaseImage(&test);
	return pos*3;
}




//not used:
//************************************
// Method:    crop
// FullName:  FindCode::crop
// Access:    public 
// Returns:   void
// Qualifier:
// Parameter: IplImage * image		--image to work with
// Parameter: IplImage * rawcrop	--storage of cropped codeblock
// Parameter: IplImage * normalized	--storage of normalized codeblock
// Parameter: int type				--type of image (telelens=0, trilens=1)
// Parameter: int codeIndex			--used for trilens, when more than one codeblock exists in one image
//
// Description: position of code is known 
//  => extraction with "magic numbers"
//************************************
/*
void FindCode::crop(IplImage *image, IplImage *rawcrop, IplImage *normalized, int type, int codeIndex)
{
	Debug::message(">>>Crop<<<",Debug::VERBOSE);
	int startx, starty;

	//type==0 -> telelens; type==1 -> trilens
	if (type == 0)
	{
		startx = 1270;
		starty = 10150;
	} else if (type == 1)
	{
		startx = 115+codeIndex*Init::getOffset();
		starty = 10150;
	}

	//extracting the code block
	for (int i=0; i<700; i++)
	{
		for (int j=0; j<440; j++)
		{
			Pixel pix = ImageUtils::getPixel(image,j+startx,i+starty);
			FindCode::minMax(pix);
			pix.y=i;
			pix.x=j;
			ImageUtils::setPixel(rawcrop,pix);
		}
	}

	if (Init::getDebug())
	{
		cvNamedWindow("test", 0);
		cvShowImage("test", rawcrop);
		cvResizeWindow( "test", rawcrop->width/2, rawcrop->height/2 );
		cvWaitKey(0);
		cvDestroyWindow("test");
	}

	//threshold image of code block
	FindCode::normalize(rawcrop, normalized, Init::getParts().x, Init::getParts().y);

	if (Init::getDebug())
	{
		cvNamedWindow("test", 0);
		cvShowImage("test", rawcrop);
		cvResizeWindow( "test", rawcrop->width/2, rawcrop->height/2 );
		cvWaitKey(0);
		cvDestroyWindow("test");
	}

}*/
